package com.yoki.cloud.common.code.generator.impl;

import com.yoki.cloud.common.code.bean.EntityBean;
import com.yoki.cloud.common.code.generator.AbstractCodeGenerator;
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.*;
import java.util.*;

/**
 * @author Sky$
 * @Description: TODO
 * @date 2018/1/24$ 10:12$
 */
public class SpringBootCodeGenerator extends AbstractCodeGenerator {

    /**
     * 保存文件路径
     */
    private static final String SAVE_PATH_PRE = "C:\\Users\\SKY\\Desktop\\code\\yoki-cloud-bg-shop-springboot\\";
    /**
     * 基础包名
     */
    private static final String BASE_PACKAGE = "com.yoki.cloud.bg.shop";

    private static final String PROJECT_NAME = "cloud-bg-shop";
    private static final String[] mvnModuleSimpleNames = {"vo", "domain",
            "infra", "application", "web-api", "web-api-impl"};
    private static final String[] mvnModuleNamespaces = {
            "vo",
            "core",
            "infra",
            "application",
            "web" + File.separator + "api",
            "web" + File.separator + "api" + File.separator + "impl" + File.separator + "rest"};
    private static final String[][] fileNamespaces = {
            {""},
            {"domain", "dto", "infra"},
            {""},
            {"", "transform"},
            {"", "command", "command", "command"},
            {"", "assembler"}};
    private static final String[][] fileNameSuffixs = {
            {"VO.java"},
            {".java", "PageQueryDTO.java", "Repository.java"},
            {"Mapper.xml"},
            {"Service.java", "VOTransform.java"},
            {"RestApi.java", "CreateCommand.java", "UpdateCommand.java", "PageCommand.java"},
            {"Controller.java", "Assembler.java"}};

    private static final String[][] fltfileNameSuffixs = {
            {"VO.ftl"},
            {"Entity.ftl", "PageQueryDTO.ftl", "Repository.ftl"},
            {"XmlMapper.ftl"},
            {"Service.ftl", "VOTransform.ftl"},
            {"RestApi.ftl", "CreateCommand.ftl", "UpdateCommand.ftl", "PageCommand.ftl"},
            {"Controller.ftl", "Assembler.ftl"}};


    private static final String GROUP_ID = "com.yoki.cloud";


    @Override
    public String getBasePackage() {
        return BASE_PACKAGE;
    }

    @Override
    public String getSavePathPre() {
        return SAVE_PATH_PRE;
    }

    @Override
    public String getFtlRelativePath() {
        return "ddd";
    }


    public static void main(String[] args) {
        SpringBootCodeGenerator generator = new SpringBootCodeGenerator();
        generator.generate();
    }

    @Override
    protected void genFiles(Map beanMap, Configuration cfg) throws IOException {
        genProj(beanMap, cfg);
    }

    private void genProj(Map beanMap, Configuration cfg) throws IOException {
        //重新生成项目路径
        File projDir = new File(getSavePathPre() + File.separator + PROJECT_NAME);
        if (projDir.exists()) {
            System.out.println("文件已存在，请手动删除后再操作!!!");
        }
        projDir.mkdirs();

        //生成pom文件
        String ftlFilePath = MgrCodeGenerator.class.getResource("/").getPath() + File.separator + "springboot";
        Configuration pomCfg = new Configuration();
        pomCfg.setNumberFormat("#");
        pomCfg.setDirectoryForTemplateLoading(new File(ftlFilePath));
        Template temEntity = pomCfg.getTemplate("POM.ftl");
        Map pomMap = new HashMap(10);
        pomMap.put("projectName", PROJECT_NAME);
        pomMap.put("groupId", GROUP_ID);
        Set<String> moduleList = new HashSet<>(10);

        Iterator<Map.Entry<String, EntityBean>> mapIter = beanMap.entrySet().iterator();
        Map<String, Map> mapMap = new HashMap<>();
        while (mapIter.hasNext()) {
            Map.Entry<String, EntityBean> mapEntity = mapIter.next();
            String key = mapEntity.getKey();
            EntityBean classBean = mapEntity.getValue();
            Map<String, EntityBean> sameModuleBeanMap = mapMap.get(classBean.getModuleName());
            if (null == sameModuleBeanMap) {
                sameModuleBeanMap = new HashMap<>();
            }
            sameModuleBeanMap.put(key, classBean);
            mapMap.put(classBean.getModuleName() , sameModuleBeanMap) ;
        }


        for (int i = 0; i < mvnModuleSimpleNames.length; i++) {
            moduleList.add(PROJECT_NAME + "-" + mvnModuleSimpleNames[i].toLowerCase());


            String mvnModuleFullName = PROJECT_NAME + "-" + mvnModuleSimpleNames[i].toLowerCase();
            String mvnModulePath = getSavePathPre()
                    + File.separator + PROJECT_NAME
                    + File.separator + mvnModuleFullName;
            Map<String, String> pathMap = genMvnModuleDir(mvnModulePath, mvnModuleFullName);
            String mvnModuleMainBasePath = pathMap.get("main");
            String mvnModuleJavaBasePath = pathMap.get("java");
            String mvnModuleResourcesBasePath = pathMap.get("resources");
            String mvnModuleBasePackagePath = pathMap.get("basePackage") +
                    File.separator + mvnModuleNamespaces[i];

            Iterator<String> keyIter = mapMap.keySet().iterator();
            while (keyIter.hasNext()) {
                String moduleName = keyIter.next();
                Map<String, EntityBean> sameModuleBeanMap = mapMap.get(moduleName);
                String mvnInfraModuleMapperPath = mvnModuleResourcesBasePath +
                        File.separator + "mapper" +
                        File.separator + moduleName;

                for (int j = 0; j < fileNamespaces[i].length; j++) {
                    String filePath = mvnModuleBasePackagePath + File.separator +
                            moduleName + File.separator + fileNamespaces[i][j];
                    if (null == fltfileNameSuffixs[i][j] || fltfileNameSuffixs[i][j].length() <= 0) {
                        continue;
                    }
                    if ("infra".equals(mvnModuleSimpleNames[i].toLowerCase())) {
                        genFile(sameModuleBeanMap, cfg, fltfileNameSuffixs[i][j],
                                mvnInfraModuleMapperPath, fileNameSuffixs[i][j]);
                    } else {
                        genFile(sameModuleBeanMap, cfg, fltfileNameSuffixs[i][j], filePath, fileNameSuffixs[i][j]);
                    }
                }
            }


        }

        pomMap.put("moduleList", moduleList);
        File pomFile = new File(projDir + File.separator + "pom.xml");
        try {
            Writer out = new OutputStreamWriter(new FileOutputStream(pomFile.getPath()), "UTF-8");
            temEntity.process(pomMap, out);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private Map<String, String> genMvnModuleDir(String mvnModulePath, String mvnModuleName) throws IOException {
        //项目module结构
        String projModuleName = mvnModuleName;
        File projModuleDir = new File(getSavePathPre()
                + File.separator + PROJECT_NAME
                + File.separator + projModuleName);
        if (!projModuleDir.exists()) {
            projModuleDir.mkdirs();
        }
        //生成pom文件
        File pomFile = new File(projModuleDir + File.separator + "pom.xml");
        if (pomFile.exists()) {
            pomFile.delete();
        }
        String ftlFilePath = MgrCodeGenerator.class.getResource("/").getPath() + File.separator + "springboot";
        Configuration pomCfg = new Configuration();
        pomCfg.setDirectoryForTemplateLoading(new File(ftlFilePath));
        Template temEntity = pomCfg.getTemplate(mvnModuleName.replace(PROJECT_NAME, "")
                .replace("-", "")
                .toLowerCase() + "POM.ftl");
        Map pomMap = new HashMap(10);
        pomMap.put("projectName", PROJECT_NAME);
        pomMap.put("projModuleName", projModuleName);
        pomMap.put("groupId", GROUP_ID);
        try {
            Writer out = new OutputStreamWriter(new FileOutputStream(pomFile.getPath()), "UTF-8");
            temEntity.process(pomMap, out);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //生成类文件加
        String mvnModuleMainBasePath = mvnModulePath + File.separator + "src" +
                File.separator + "main";
        String mvnModuleJavaBasePath = mvnModuleMainBasePath +
                File.separator + "java";
        String mvnModuleResourcesBasePath = mvnModuleMainBasePath +
                File.separator + "resources";
        String mvnModuleBasePackagePath = mvnModuleJavaBasePath +
                File.separator + BASE_PACKAGE.replace(".", File.separator);

        File mvnModuleBasePackageFile = new File(mvnModuleBasePackagePath);
        if (!mvnModuleBasePackageFile.exists()) {
            mvnModuleBasePackageFile.mkdirs();
        }
        File mvnModuleResourcesBaseFile = new File(mvnModuleResourcesBasePath);
        if (!mvnModuleResourcesBaseFile.exists()) {
            mvnModuleResourcesBaseFile.mkdirs();
        }
        Map<String, String> pathMap = new HashMap<>();
        pathMap.put("main", mvnModuleMainBasePath);
        pathMap.put("java", mvnModuleJavaBasePath);
        pathMap.put("resources", mvnModuleResourcesBasePath);
        pathMap.put("basePackage", mvnModuleBasePackagePath);
        return pathMap;
    }


    /**
     * 先根遍历序递归删除文件夹
     *
     * @param dirFile 要被删除的文件或者目录
     * @return 删除成功返回true, 否则返回false
     */
    public static boolean deleteFile(File dirFile) {
        // 如果dir对应的文件不存在，则退出
        if (!dirFile.exists()) {
            return false;
        }
        if (dirFile.isFile()) {
            return dirFile.delete();
        } else {
            for (File file : dirFile.listFiles()) {
                deleteFile(file);
            }
        }
        return dirFile.delete();
    }

}
